package contegor.scire.structure;

import java.util.List;
import java.util.Map;
import java.util.Set;

import contegor.scire.core.Container;
import contegor.scire.core.DuplicateElementException;
import contegor.scire.core.Id;
import contegor.scire.core.Link;
import contegor.scire.core.MissingElementException;
import contegor.scire.core.ReturnPoint;
import contegor.scire.core.Task;
import contegor.scire.core.TaskId;
import contegor.scire.core.TransactionId;
import contegor.scire.core.Version;
import contegor.scire.core.WrongStateException;
import contegor.scire.core.modifications.Modification;


/**
 * Defines a concept cloud. It will contain a set of {@link Container}s with a common root. A cloud will hold a
 * knowledge set like 'core concepts', 'user collection', etc. It can bee connected to other clouds through
 * {@link DockingModule}s.
 *
 * @version $Revision: 1.3 $
 * @author  Héctor Cirbián Pousa ($Author: hector $)
 */
@Version("$Id: Cloud.java,v 1.3 2010-02-01 10:55:42 hector Exp $")
public interface ConceptCloud {

  /**
   * This method is used when {@link ConceptCloud}s are connected through a {@link DockingModule}. With it, 
   * a {@link ConceptCloud} can update its external link tracking structure so it shows the {@link Link}s from
   * the other {@link ConceptCloud}s pointing it. It returns a {@link List} of {@link Task}s that will perform
   * the necessary updates in the other and target {@link ConceptCloud} so it is updated accordingly.
   * 
   * During connection with other {@link ConceptCloud}, {@link Modification}s for creation of new {@link Link}s
   * between them should not be executed.
   * 
   * @param root {@link Id} of the other {@link ConceptCloud}.
   * @return {@link List} of {@link Task}s that if processed by the target {@link ConceptCloud}, will know which external
   *         references it has. 
   */
  public List<Task<Void>> getLinkTrackingTasksFor(Id root);


  /**
   * This method should be used when a {@link ConceptCloud} closes its connection with other. With it,
   * <code>this</code> will stop tracking links from other {@link ConceptCloud} which root is the one
   * passed as parameter.
   * 
   * @param root {@link Id} of the {@link ConceptCloud} to which the connection is closed.
   */
  public void stopTrackingLinksOf(Id root);

  /**
   * Gives the {@link Id} of the root {@link Container} in this {@link ConceptCloud}.
   * 
   * @return {@link Id} of the root {@link Container} in this {@link ConceptCloud}.
   */
  public Id getRootId();

  /**
   * Process a {@link Task} send to the {@link ConceptCloud}. This can be an asynchronous method.
   * The processing results are returned through the {@link ReturnPoint} parameter, also any exception
   * that happens processing the task. 
   *
   * @param <T> The {@link Task} and the {@link ReturnPoint} must work with the same type.
   * @param msg {@link Task} to be processed.
   * @param rp {@link ReturnPoint} through with the results will be delivered.
   */
  public <T> void process(Task<T> task, ReturnPoint<? super T> rp);

  /**
   * Commits the transaction related with the {@link TaskId} in all {@link Container}s inside this
   * {@link ConceptCloud}.
   * Any {@link Exception} that happens during the commit will be thrown.
   */
  public void commit(TaskId taskId) throws Exception;

  /**
   * Rolls back the transaction related with the {@link TaskId} in all {@link Container}s inside this
   * {@link ConceptCloud}.
   * Any {@link Exception} that happens during the commit will be thrown.
   */
  public void rollback(TaskId taskId) throws Exception;

  /**
   * Creates a new {@link Container} inside the {@link ConceptCloud}.
   * 
   * @param id {@link Id} of the new {@link Container}.
   * @throws MissingElementException if there is not a parent container for the new one.
   * @throws DuplicateElementException
   * @throws WrongStateException
   */
  public void createContainer(Id id) throws MissingElementException, DuplicateElementException, WrongStateException;

  /**
   * With this method a {@link ConceptCloud} can dock to a {@link DockingModule} and establish a connection
   * with other {@link ConceptCloud}s all ready connected with it.
   *
   * @param dockingModule {@link DockingModule} to which <code>this</code> will dock.
   * @throws WrongStateException if <code>this</code> or the {@link DockingModule} are not prepared for the connection.
   */
  public void dock(DockingModule dockingModule) throws WrongStateException;

  /**
   * Method to release a hook with a {@link DockingModule}.
   * 
   * @param dockingModule from which the hook will be release.
   * @throws WrongStateException if there are not finished {@link Task}s delivered through the connection, or
   *         there was not such connection.
   */
  public void release(DockingModule dockingModule) throws WrongStateException;

  /** For test proposes */
  public Map<Id, Set<TransactionId>> getPendingTransactions();
}
